﻿using System.Modules.SharePoint.Constants;
using System.Modules.SharePoint.Contracts.Enums;
using System.Text;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;

namespace System.Modules.SharePoint.Contracts.DTO
{
    /// <summary>
    /// Use this Class to Build SP Query
    /// </summary>
    public class SPQueryBuilder
    {
        #region Properties
        /// <summary>
        /// Holds the condition string
        /// </summary>
        public SPQueryCondition Condition { get; set; }

        /// <summary>
        /// Holds the order by condition
        /// </summary>
        public SPQueryOrderFieldsCollection OrderFields { get; set; }

        /// <summary>
        /// Holds the View Fields
        /// </summary>
        public SPQueryViewFieldsCollection ViewFields { get; set; }

        /// <summary>
        /// Row Limit
        /// </summary>
        public uint? RowLimit { get; set; }

        /// <summary>
        /// View Scope
        /// </summary>
        public SPViewScope? ViewScope { get; set; }

        /// <summary>
        /// ExpandRecurrence
        /// </summary>
        public bool? ExpandRecurrence { get; set; }

        /// <summary>
        /// CalendarDate
        /// </summary>
        public DateTime? CalendarDate { get; set; }
        #endregion

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the SPQueryBuilder class.
        /// </summary>
        public SPQueryBuilder() { }

        /// <summary>
        /// Initializes a new instance of the SPQueryBuilder class.
        /// </summary>
        /// <param name="fieldName">The field name</param>
        /// <param name="fieldValue">The field value</param>
        /// <param name="fieldType">The field type</param>
        public SPQueryBuilder(string fieldName, string fieldValue, SPFieldType fieldType)
        {
            Condition = new SPQueryOperation(fieldName, fieldValue, fieldType, SPQueryCamlOperation.Eq);
        }

        /// <summary>
        /// Initializes a new instance of the SPQueryBuilder class.
        /// </summary>
        /// <param name="fieldName">The field name</param>
        /// <param name="fieldValue">The field value</param>
        /// <param name="fieldType">The field type</param>
        /// <param name="operation">The operation used</param>
        public SPQueryBuilder(string fieldName, string fieldValue, SPFieldType fieldType, SPQueryCamlOperation operation)
        {
            Condition = new SPQueryOperation(fieldName, fieldValue, fieldType, operation);
        }

        /// <summary>
        /// Initializes a new instance of the SPQueryBuilder class.
        /// </summary>
        /// <param name="fieldName">The field name</param>
        /// <param name="fieldValue">The field value</param>
        /// <param name="fieldType">The field type</param>
        /// <param name="operation">The operation used</param>
        /// <param name="isLookupId"> </param>
        public SPQueryBuilder(string fieldName, string fieldValue, SPFieldType fieldType, SPQueryCamlOperation operation, bool isLookupId)
        {
            Condition = new SPQueryOperation(fieldName, fieldValue, fieldType, operation, isLookupId);
        }
        #endregion

        #region Implicit Operators
        /// <summary>
        /// Implicit conversion operator to string
        /// </summary>
        /// <param name="query">The CamlBuidler object</param>
        /// <returns>A string representation of the caml object</returns>
        public static implicit operator string(SPQueryBuilder query)
        {
            return query == null ? string.Empty : query.ToString();
        }

        /// <summary>
        /// Implicit conversion operator to SPQuery
        /// </summary>
        /// <param name="query">The CamlBuidler object</param>
        /// <returns>SPQuery with the query set to the caml</returns>
        public static implicit operator SPQuery(SPQueryBuilder query)
        {
            return query == null ? null : query.ToSPQuery();
        }
        #endregion

        #region Methods
        #region Add View Field
        /// <summary>
        /// Adds a View Field
        /// </summary>
        /// <param name="fieldName">The field name</param>
        public void AddViewField(string fieldName)
        {
            if (ViewFields == null) { ViewFields = new SPQueryViewFieldsCollection(); }
            ViewFields.Add(new SPQueryFieldRef { FieldName = fieldName });
        }
        #endregion

        #region AND
        /// <summary>
        /// Adds an And condition
        /// </summary>
        /// <param name="condition">The condition to add</param>
        public void And(SPQueryCondition condition)
        {
            if (Condition != null)
            {
                var newCondition = new SPQueryAnd();
                newCondition.FirstCondition = Condition;
                newCondition.SecondCondition = condition;
                Condition = newCondition;
            }
            else
            {
                Condition = condition;
            }
        }

        /// <summary>
        /// Adds an And condition
        /// </summary>
        /// <param name="fieldName">The field name</param>
        /// <param name="fieldValue">The field value</param>
        /// <param name="fieldType">The field type</param>
        public void And(string fieldName, string fieldValue, SPFieldType fieldType)
        {
            And(fieldName, fieldValue, fieldType, SPQueryCamlOperation.Eq);
        }

        /// <summary>
        /// Adds an And condition
        /// </summary>
        /// <param name="fieldName">The field name</param>
        /// <param name="fieldValue">The field value</param>
        /// <param name="fieldType">The field type</param>
        /// <param name="operation">The operation</param>
        public void And(string fieldName, string fieldValue, SPFieldType fieldType, SPQueryCamlOperation operation)
        {
            And(fieldName, fieldValue, fieldType, operation, false);
        }

        /// <summary>
        /// Adds an And condition
        /// </summary>
        /// <param name="fieldName">The field name</param>
        /// <param name="fieldValue">The field value</param>
        /// <param name="fieldType">The field type</param>
        /// <param name="operation">The operation</param>
        /// <param name="isLookupId"> </param>
        public void And(string fieldName, string fieldValue, SPFieldType fieldType, SPQueryCamlOperation operation, bool isLookupId)
        {
            And(new SPQueryOperation(fieldName, fieldValue, fieldType, operation, isLookupId));
        }
        #endregion

        #region OR
        /// <summary>
        /// Adds an Or condition
        /// </summary>
        /// <param name="condition">The condition to add</param>
        public void Or(SPQueryCondition condition)
        {
            if (Condition != null)
            {
                var newCondition = new SPQueryOr();
                newCondition.FirstCondition = Condition;
                newCondition.SecondCondition = condition;
                Condition = newCondition;
            }
            else
            {
                Condition = condition;
            }
        }

        /// <summary>
        /// Adds an Or condition
        /// </summary>
        /// <param name="fieldName">The field name</param>
        /// <param name="fieldValue">The field value</param>
        /// <param name="fieldType">The field type</param>
        public void Or(string fieldName, string fieldValue, SPFieldType fieldType)
        {
            Or(fieldName, fieldValue, fieldType, SPQueryCamlOperation.Eq);
        }

        /// <summary>
        /// Adds an Or condition
        /// </summary>
        /// <param name="fieldName">The field name</param>
        /// <param name="fieldValue">The field value</param>
        /// <param name="fieldType">The field type</param>
        /// <param name="operation">The operation</param>
        public void Or(string fieldName, string fieldValue, SPFieldType fieldType, SPQueryCamlOperation operation)
        {
            Or(fieldName, fieldValue, fieldType, operation, false);
        }

        /// <summary>
        /// Adds an Or condition
        /// </summary>
        /// <param name="fieldName">The field name</param>
        /// <param name="fieldValue">The field value</param>
        /// <param name="fieldType">The field type</param>
        /// <param name="operation">The operation</param>
        /// <param name="isLookupId"> </param>
        public void Or(string fieldName, string fieldValue, SPFieldType fieldType, SPQueryCamlOperation operation, bool isLookupId)
        {
            Or(new SPQueryOperation(fieldName, fieldValue, fieldType, operation, isLookupId));
        }
        #endregion

        #region Order By
        /// <summary>
        /// Adds an order by condition
        /// </summary>
        /// <param name="fieldName">The field name</param>
        /// <param name="direction">The direction of sorting</param>
        public void OrderBy(string fieldName, SortDirection direction)
        {
            if (OrderFields == null) { OrderFields = new SPQueryOrderFieldsCollection(); }
            OrderFields.Add(new SPQueryFieldRef { FieldName = fieldName, Direction = direction });
        }
        #endregion

        #region To SPQuery
        /// <summary>
        /// Convertt the SP Query Builder to SPQuery
        /// </summary>
        public SPQuery ToSPQuery()
        {
            var value = new SPQuery { Query = ToString() };
            if (ViewScope.HasValue)
            {
                value.ViewAttributes = string.Format(SPQueryTemplateAttributes.VIEW_SCOPE, ViewScope);
            }
            if (ExpandRecurrence.HasValue)
            {
                value.ExpandRecurrence = ExpandRecurrence.Value;
            }
            if (CalendarDate.HasValue)
            {
                value.CalendarDate = CalendarDate.Value;
            }
            if (ViewFields != null)
            {
                value.ViewFields = ViewFields;
            }
            if (RowLimit.HasValue)
            {
                value.RowLimit = RowLimit.Value;
            }
            return value;
        }
        #endregion
        #endregion

        #region Override
        /// <summary>
        /// Get the string representation
        /// </summary>
        /// <returns>The string representation</returns>
        public override string ToString()
        {
            var query = new StringBuilder();
            if (Condition != null)
            {
                query.AppendFormat(SPQueryTemplates.WHERE, Condition);
            }
            if (OrderFields != null)
            {
                query.AppendFormat(SPQueryTemplates.ORDER_BY, OrderFields);
            }
            return query.ToString();
        }
        #endregion
    }
}